/**
 * *****************************************************************************
 * Copyright 2011 See AUTHORS file.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *****************************************************************************
 */
package sg.atom.utils.datastructure.collection;

/**
 * An {@link ObjectMap} that also stores keys in an {@link Array} using the
 * insertion order. There is some additional overhead for put and remove.
 * Iteration over the {@link #entries()}, {@link #keys()}, and {@link #values()}
 * is ordered. Keys can also be accessed and the order changed using
 * {@link #orderedKeys()}.
 *
 * <p>FIXME: Replace with Map view of OrderedSet!
 * 
 * @author Nathan Sweet
 */@Deprecated
public class OrderedMap<K, V> extends ObjectMap<K, V> {

    final Array<K> keys;

    public OrderedMap() {
        super();
        keys = new Array();
    }

    public OrderedMap(int initialCapacity) {
        super(initialCapacity);
        keys = new Array(initialCapacity);
    }

    public OrderedMap(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor);
        keys = new Array(initialCapacity);
    }

    public V put(K key, V value) {
        if (!containsKey(key)) {
            keys.add(key);
        }
        return super.put(key, value);
    }

    public V remove(K key) {
        keys.removeValue(key, false);
        return super.remove(key);
    }

    public void clear() {
        keys.clear();
        super.clear();
    }

    public Array<K> orderedKeys() {
        return keys;
    }

    public Entries<K, V> entries() {
        return new Entries(this) {
            void advance() {
                nextIndex++;
                hasNext = nextIndex < map.size;
            }

            public Entry next() {
                entry.key = keys.get(nextIndex);
                entry.value = map.get(entry.key);
                advance();
                return entry;
            }

            public void remove() {
                map.remove(entry.key);
            }
        };
    }

    public Keys<K> keys() {
        return new Keys(this) {
            void advance() {
                nextIndex++;
                hasNext = nextIndex < map.size;
            }

            public K next() {
                K key = keys.get(nextIndex);
                advance();
                return key;
            }

            public void remove() {
                map.remove(keys.get(nextIndex - 1));
            }
        };
    }

    public Values<V> values() {
        return new Values(this) {
            void advance() {
                nextIndex++;
                hasNext = nextIndex < map.size;
            }

            public V next() {
                V value = (V) map.get(keys.get(nextIndex));
                advance();
                return value;
            }

            public void remove() {
                map.remove(keys.get(nextIndex - 1));
            }
        };
    }

    public String toString() {
        if (size == 0) {
            return "{}";
        }
        StringBuilder buffer = new StringBuilder(32);
        buffer.append('{');
        Array<K> keys = this.keys;
        for (int i = 0, n = keys.size; i < n; i++) {
            K key = keys.get(i);
            if (i > 0) {
                buffer.append(", ");
            }
            buffer.append(key);
            buffer.append('=');
            buffer.append(get(key));
        }
        buffer.append('}');
        return buffer.toString();
    }
}
